package gota;

import java.net.URL;
import java.util.ArrayList;

import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathFactory;

import org.w3c.dom.*;

import gate.Corpus;
import gate.Document;
import gate.Factory;
import gate.creole.SerialAnalyserController;
import gate.util.GateException;
import gota.processingResources.IProcessingResource;
import gota.util.GenericUtil;

public class ResourceLoader {
	private SerialAnalyserController controller;
	private org.w3c.dom.Document document;
	private XPath xpath;
	private Corpus corpus;
	private ArrayList<Document> documentList;

	public void init(SerialAnalyserController controller,
			org.w3c.dom.Document document) {
		xpath = XPathFactory.newInstance().newXPath();
		this.controller = controller;
		this.document = document;
	}

	public void LoadResources() throws Exception {
		loadProcessingResources();

		corpus = Factory.newCorpus("Documents");
		documentList = new ArrayList<Document>();
		controller.setCorpus(corpus);
		loadDocuments();
	}

	public Corpus getCorpus() {
		return corpus;
	}

	public ArrayList<Document> getDocuments(){
		return documentList;
	}
	
	@SuppressWarnings("unchecked")
	private void loadDocuments() throws Exception {
		String documentExpression = "/GotaConfig/Documents";
		Node documentNode = (Node) xpath.evaluate(
				documentExpression, document, XPathConstants.NODE);
		
		if (documentExpression == null)
			return;
		
		NodeList documentsNode = (NodeList) xpath.evaluate(
				"//Document", documentNode, XPathConstants.NODESET);
		for(int i=0; i< documentsNode.getLength();i++){
			Node document = documentsNode.item(i);
			if(document.getNodeType() != Node.ELEMENT_NODE)
				continue;
			
			NamedNodeMap attributeMap = document.getAttributes();
			Document createdDocument = null;
			String contentType = null;
			String encoding = null;
			for(int j = 0; j < attributeMap.getLength(); j++){
				Node attributeNode = attributeMap.item(j);
				if(attributeNode.getNodeType() != Node.ATTRIBUTE_NODE)
					continue;
				
				String attributeName = attributeNode.getNodeName();
				if(attributeName.equals("type")){
					String attributeValue = attributeNode.getNodeValue();
					if(attributeValue.equals("Text")){
						contentType = "Text";
					}
					else if(attributeValue.equals("Url")){
						contentType = "Url";						
					}
				}
				else if(attributeName.equals("encoding")){
					encoding=attributeNode.getTextContent();
				}
			}
			
			if(contentType.equals("Text")){
				createdDocument = Factory.newDocument(document.getTextContent());
			} else if(contentType.equals("Url")){
				URL docUri = new URL(document.getTextContent());
				createdDocument = Factory.newDocument(docUri, encoding);
			}
			
			if(createdDocument != null){
				corpus.add(createdDocument);
				documentList.add(createdDocument);
			}
		}

	}

	@SuppressWarnings("unchecked")
	private void loadProcessingResources() throws Exception {
		String resourceExpression = "/GotaConfig/Resources";
		Node resourcesNode = (Node) xpath.evaluate(
				resourceExpression, document, XPathConstants.NODE);
		if (resourcesNode == null)
			throw new GateException("Not valid configuration xml");

		Class[] processingClasses = GenericUtil.GetClassesOfType(
				"gota.processingResources", IProcessingResource.class);
		ArrayList<IProcessingResource> processingResourceInstances = new ArrayList<IProcessingResource>();
		for (int i = 0; i < processingClasses.length; i++) {
			processingResourceInstances
					.add((IProcessingResource) processingClasses[i]
							.newInstance());
		}

		// ForAll Resources
		NodeList resourceNodes = resourcesNode.getChildNodes();
		for (int i = 0; i < resourceNodes.getLength(); i++) {
			Node resourceNode = resourceNodes.item(i);
			if (resourceNode.getNodeType() != Node.ELEMENT_NODE)
				continue;

			String resourceName = resourceNode.getNodeName();
			IProcessingResource processingResource = null;
			for (IProcessingResource tmpResource : processingResourceInstances) {
				if (tmpResource.getResourceName().equals(resourceName)) {
					processingResource = tmpResource;
					break;
				}
			}

			if (processingResource == null) {
				throw new GateException(String.format(
						"Couldn't find resourceName : %s", resourceName));
			}

			processingResource.init(controller, resourceNode);
		}
	}
}
